package ccm.tools;

import ccm.common.CCMConfigManager;
import ccm.component.image.AutoResizeableImageJPanel;
import ccm.component.image.ImageJPanel;
import ccm.component.image.ManualResizeableImageJPanel;
import ccm.component.override.JButton;
import ccm.component.override.JCheckBox;
import ccm.component.override.JComboBox;
import ccm.component.override.JFrame;
import ccm.component.override.JLabel;
import ccm.component.override.JSpinner;
import ccm.component.override.JTextField;
import ccm.component.override.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class GenerateImage extends JFrame implements ActionListener, ChangeListener
{
    private static final String[] title=new String[]{
            "tools",
            "GenerateImage"
    };

    static
    {
        CCMConfigManager.setStringIfAbsent("ccm/tools/GenerateImage/lastDir","");
    }

    protected final ImageJPanel imageSourceJPanel;
    protected final ImageJPanel imageResultJPanel;
    protected final JButton openJButton;
    protected final JSpinner widthJSpinner;
    protected final JComboBox<Integer> rotateJComboBox;
    protected final JComboBox<String> templeJComboBox;
    protected final JCheckBox mirrorJCheckBox;
    protected final JCheckBox staticJCheckBox;
    protected final JCheckBox fixedJCheckBox;
    protected final JTextField functionNameJTextField;
    protected final JTextField fixedXJTextField;
    protected final JTextField fixedYJTextField;
    protected final JTextField fixedWJTextField;
    protected final JTextField fixedHJTextField;
    protected final JTextField fixedLJTextField;
    protected final JCheckBox autoSaveJCheckBox;
    protected final JButton saveJButton;
    protected final JLabel infoJLabel;
    protected String lastSelectedFile;

    public GenerateImage()
    {
        super(title);
        setLayout(new BorderLayout());
        JSplitPane jSplitPane=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        add(jSplitPane,BorderLayout.CENTER);
        jSplitPane.setDividerLocation(0.5);
        jSplitPane.setEnabled(false);
        addComponentListener(new ComponentAdapter()
        {
            public void componentResized(ComponentEvent e)
            {
                jSplitPane.setDividerLocation(0.5);
            }
        });


        jSplitPane.add(imageSourceJPanel=new AutoResizeableImageJPanel());
        jSplitPane.add(imageResultJPanel=new ManualResizeableImageJPanel());

        JPanel jPanel=new JPanel();
        add(jPanel,BorderLayout.EAST);
        jPanel.setLayout(new VFlowLayout());

        openJButton=new JButton("打开");
        jPanel.add(openJButton);
        openJButton.addActionListener(this);

        jPanel.add(new JLabel("模板"));
        templeJComboBox=new JComboBox<String>(new String[]{
                "",
                "菜单锁屏",
                "直接显示",
        });
        jPanel.add(templeJComboBox);
        templeJComboBox.addActionListener(this);

        jPanel.add(new JLabel("存储尺寸"));
        widthJSpinner=new JSpinner(new SpinnerNumberModel(CCMConfigManager.setIntegerIfAbsent("ccm/tools/GenerateImage/widthJSpinner",90),0,10000,1));
        jPanel.add(widthJSpinner);
        widthJSpinner.addChangeListener(this);

        jPanel.add(new JLabel("旋转"));
        rotateJComboBox=new JComboBox<Integer>(new Integer[]{
                0,
                90,
                180,
                270
        });
        rotateJComboBox.setSelectedItem(CCMConfigManager.setIntegerIfAbsent("ccm/tools/GenerateImage/rotateJComboBox",0));
        jPanel.add(rotateJComboBox);
        rotateJComboBox.addActionListener(this);


        mirrorJCheckBox=new JCheckBox("镜像",CCMConfigManager.setBooleanIfAbsent("ccm/tools/GenerateImage/mirrorJCheckBox",false));
        jPanel.add(mirrorJCheckBox);
        mirrorJCheckBox.addActionListener(this);

        staticJCheckBox=new JCheckBox("static",CCMConfigManager.setBooleanIfAbsent("ccm/tools/GenerateImage/staticJCheckBox",true));
        jPanel.add(staticJCheckBox);
        staticJCheckBox.addActionListener(this);

        functionNameJTextField=new JTextField(CCMConfigManager.setStringIfAbsent("ccm/tools/GenerateImage/functionNameJTextField","function"),20);
        jPanel.add(functionNameJTextField);
        functionNameJTextField.addActionListener(this);


        fixedJCheckBox=new JCheckBox("固定坐标",CCMConfigManager.setBooleanIfAbsent("ccm/tools/GenerateImage/fixedJCheckBox",true));
        jPanel.add(fixedJCheckBox);
        fixedJCheckBox.addActionListener(this);

        jPanel.add(new JLabel("x"));
        fixedXJTextField=new JTextField(CCMConfigManager.setStringIfAbsent("ccm/tools/GenerateImage/fixedXJTextField","0"),20);
        jPanel.add(fixedXJTextField);
        fixedXJTextField.addActionListener(this);

        jPanel.add(new JLabel("y"));
        fixedYJTextField=new JTextField(CCMConfigManager.setStringIfAbsent("ccm/tools/GenerateImage/fixedYJTextField","0"),20);
        jPanel.add(fixedYJTextField);
        fixedYJTextField.addActionListener(this);

        jPanel.add(new JLabel("w"));
        fixedWJTextField=new JTextField(CCMConfigManager.setStringIfAbsent("ccm/tools/GenerateImage/fixedWJTextField","0"),20);
        jPanel.add(fixedWJTextField);
        fixedWJTextField.addActionListener(this);

        jPanel.add(new JLabel("h"));
        fixedHJTextField=new JTextField(CCMConfigManager.setStringIfAbsent("ccm/tools/GenerateImage/fixedHJTextField","0"),20);
        jPanel.add(fixedHJTextField);
        fixedHJTextField.addActionListener(this);

        jPanel.add(new JLabel("lay"));
        fixedLJTextField=new JTextField(CCMConfigManager.setStringIfAbsent("ccm/tools/GenerateImage/fixedHJTextField","SCNS_LCD_LAYER_0"),20);
        jPanel.add(fixedLJTextField);
        fixedLJTextField.addActionListener(this);


        autoSaveJCheckBox=new JCheckBox("自动保存",CCMConfigManager.setBooleanIfAbsent("ccm/tools/GenerateImage/autoSaveJCheckBox",false));
        jPanel.add(autoSaveJCheckBox);
        autoSaveJCheckBox.addActionListener(this);


        saveJButton=new JButton("保存");
        jPanel.add(saveJButton);
        saveJButton.addActionListener(this);

        add(infoJLabel=new JLabel("",SwingConstants.RIGHT),BorderLayout.SOUTH);
        infoJLabel.setFont(new Font("",Font.PLAIN,20));

        lastSelectedFile=CCMConfigManager.setStringIfAbsent("ccm/tools/GenerateImage/lastSelectedFile","");
        try
        {
            imageSourceJPanel.setImage(ImageIO.read(new File(lastSelectedFile)));
        }catch(IOException e)
        {
            e.printStackTrace();
        }
        update();
        setVisible(true);
    }

    public static void main(String[] args)
    {
        new GenerateImage();
    }

    public String[] getTitleArray()
    {
        return title;
    }

    public void writeConfig()
    {
        CCMConfigManager.setBoolean("ccm/tools/GenerateImage/mirrorJCheckBox",mirrorJCheckBox.isSelected());
        CCMConfigManager.setBoolean("ccm/tools/GenerateImage/staticJCheckBox",staticJCheckBox.isSelected());
        CCMConfigManager.setBoolean("ccm/tools/GenerateImage/autoSaveJCheckBox",autoSaveJCheckBox.isSelected());
        CCMConfigManager.setBoolean("ccm/tools/GenerateImage/fixedJCheckBox",fixedJCheckBox.isSelected());
        CCMConfigManager.setInteger("ccm/tools/GenerateImage/widthJSpinner",(int)widthJSpinner.getValue());
        CCMConfigManager.setInteger("ccm/tools/GenerateImage/rotateJComboBox",(int)rotateJComboBox.getSelectedItem());
        CCMConfigManager.setString("ccm/tools/GenerateImage/lastSelectedFile",lastSelectedFile);
        CCMConfigManager.setString("ccm/tools/GenerateImage/functionNameJTextField",functionNameJTextField.getText());
        CCMConfigManager.setString("ccm/tools/GenerateImage/fixedXJTextField",fixedXJTextField.getText());
        CCMConfigManager.setString("ccm/tools/GenerateImage/fixedYJTextField",fixedYJTextField.getText());
        CCMConfigManager.setString("ccm/tools/GenerateImage/fixedHJTextField",fixedHJTextField.getText());
        CCMConfigManager.setString("ccm/tools/GenerateImage/fixedWJTextField",fixedWJTextField.getText());
        CCMConfigManager.setString("ccm/tools/GenerateImage/fixedLJTextField",fixedLJTextField.getText());
    }

    public void actionPerformed(ActionEvent e)
    {
        if(e.getSource().equals(openJButton))
        {
            JFileChooser jFileChooser=new JFileChooser(lastSelectedFile);
            jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            jFileChooser.showDialog(new JLabel(),"选择");
            try
            {
                final File selectedFile=jFileChooser.getSelectedFile();
                lastSelectedFile=selectedFile.getAbsolutePath();
                imageSourceJPanel.setImage(ImageIO.read(selectedFile));
            }catch(IOException ex)
            {
                ex.printStackTrace();
            }
        }
        else if(e.getSource().equals(templeJComboBox))
        {
            switch((String)templeJComboBox.getSelectedItem())
            {
                case "菜单锁屏":
                    staticJCheckBox.setSelected(false);
                    functionNameJTextField.setText("scnsBspMenuLcdShutdown");
                    fixedJCheckBox.setSelected(true);
                    fixedXJTextField.setText("0");
                    fixedYJTextField.setText("0");
                    fixedWJTextField.setText("scnsLcdGetBorder().x");
                    fixedHJTextField.setText("scnsLcdGetBorder().y");
                    fixedLJTextField.setText("SCNS_BSP_MENU_DISPLAY_LAYER");
                    break;
                case "直接显示":
                    staticJCheckBox.setSelected(true);
                    functionNameJTextField.setText("display");
                    fixedJCheckBox.setSelected(true);
                    fixedXJTextField.setText("0");
                    fixedYJTextField.setText("0");
                    fixedWJTextField.setText("0");
                    fixedHJTextField.setText("0");
                    fixedLJTextField.setText("SCNS_LCD_LAYER_0");
                    break;
            }
        }
        update();
        if(e.getSource().equals(saveJButton))
        {
            final String aaa=save();
            if(aaa!=null)
            {JOptionPane.showMessageDialog(this,aaa,"保存成功",JOptionPane.PLAIN_MESSAGE);}

        }
    }

    protected int gcd(int a,int b)
    {
        return (b==0)?a:gcd(b,a%b);
    }

    protected String save()
    {
        try
        {
            BufferedImage image=imageResultJPanel.getImage();
            if(image==null)
            {return null;}
            File file=new File("image.c");
            if(!file.exists())
            {
                file.createNewFile();
            }

            final int w=image.getWidth();
            final int h=image.getHeight();

            StringBuilder tmp=new StringBuilder();
            tmp.append("//@formatter:off\n");
            tmp.append("#ifdef ____\n");
            tmp.append("#undef ____\n");
            tmp.append("#endif\n");
            tmp.append("#define ____ scnsLcdColorARGBToScreen\n");
            tmp.append("//").append(new File(lastSelectedFile).getName()).append('\n');
            if(staticJCheckBox.isSelected())
                tmp.append("static ");
            tmp.append("void ").append(functionNameJTextField.getText());
            if(fixedJCheckBox.isSelected())
                tmp.append("(void){\n    Point plu={").append(fixedXJTextField.getText()).append(",").append(fixedYJTextField.getText()).append("};uint16 disW=").append(fixedWJTextField.getText()).append(",disH=").append(fixedHJTextField.getText()).append(";ScnsLcdLayer layN=").append(fixedYJTextField.getText()).append(";\n    ");
            else
                tmp.append("(ScnsLcdLayer layN,Point plu,uint16 disW,uint16 disH){\n    ");
            tmp.append("if(disW==0&&disH==0){disW=").append(w).append(";disH=").append(h).append(";}else if(disH==0)disH=disW*").append(h).append("/").append(w).append(";else if(disW==0)disW=disH*").append(w).append("/").append(h).append(";plu.x=scnsMin(plu.x,scnsLcdGetBorder().x-disW);plu.y=scnsMin(plu.y,scnsLcdGetBorder().y-disH);\n    ");

            tmp.append("static const ScnsLcdColor data[]={\n        ");
            for(int i=0;i<h;++i)
                for(int j=0;j<w;++j)
                {
                    int r=(image.getRGB(j,i)>>16)&0XFF;
                    int g=(image.getRGB(j,i)>>8)&0XFF;
                    int b=(image.getRGB(j,i))&0XFF;
                    tmp.append(String.format("____(0XFF,0X%02X,0X%02X,0X%02X),",r,g,b));
                    if((i*w+j+1)%128==0)
                        tmp.append("\n        ");
                }
            tmp.append("};\n    ");

            tmp.append("scnsLcdDisplayArrayImage(layN,plu,data,SCNS_LCD_COLOR_FORMAT,NULL,").append(w).append(",").append(h).append(",disW,disH,0);\n}\n");
            tmp.append("#undef ____\n");
            tmp.append("\n//@formatter:on\n");


            BufferedWriter bufferWritter=new BufferedWriter(new FileWriter("image.c"));
            bufferWritter.write(tmp.toString());
            bufferWritter.close();
            String str="Save "+tmp.toString().length()+" bytes to image.c";
            System.out.println(str);
            return str;
        }catch(IOException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }

    private void update()
    {
        fixedXJTextField.setEnabled(fixedJCheckBox.isSelected());
        fixedYJTextField.setEnabled(fixedJCheckBox.isSelected());
        fixedLJTextField.setEnabled(fixedJCheckBox.isSelected());
        fixedWJTextField.setEnabled(fixedJCheckBox.isSelected());
        fixedHJTextField.setEnabled(fixedJCheckBox.isSelected());
        BufferedImage image=imageSourceJPanel.getImage();
        if(image==null){return;}
        writeConfig();
        final BufferedImage rotate=image=getRotateImage(image,(Integer)rotateJComboBox.getSelectedItem());
        image=getMirrorImage(image,mirrorJCheckBox.isSelected());
        final int w=(int)widthJSpinner.getValue();
        final int h=image.getHeight()*w/image.getWidth();
        image=getScaledImage(image,w,h);
        imageResultJPanel.setImage(image);

        {
            final int g=gcd(rotate.getWidth(),rotate.getHeight());
            infoJLabel.setText(String.format("S:%d*%d|T:%d*%d|%d:%d",rotate.getWidth(),rotate.getHeight(),image.getWidth(),image.getHeight(),rotate.getWidth()/g,rotate.getHeight()/g));
        }
        if(autoSaveJCheckBox.isSelected()){save();}
    }

    private BufferedImage getMirrorImage(BufferedImage srcImg,boolean mirror)
    {
        if(!mirror)
        {return srcImg;}
        BufferedImage resizedImg=new BufferedImage(srcImg.getWidth(),srcImg.getHeight(),BufferedImage.TRANSLUCENT);
        for(int i=0;i<srcImg.getWidth();++i)
        {
            for(int j=0;j<srcImg.getHeight();++j)
            {resizedImg.setRGB(srcImg.getWidth()-1-i,j,srcImg.getRGB(i,j));}
        }
        return resizedImg;
    }

    private BufferedImage getRotateImage(BufferedImage srcImg,int angle)
    {
        if(angle==0)
        {return srcImg;}
        else if(angle==90)
        {
            BufferedImage resizedImg=new BufferedImage(srcImg.getHeight(),srcImg.getWidth(),BufferedImage.TRANSLUCENT);
            for(int i=0;i<srcImg.getWidth();++i)
            {
                for(int j=0;j<srcImg.getHeight();++j)
                {resizedImg.setRGB(srcImg.getHeight()-1-j,i,srcImg.getRGB(i,j));}
            }
            return resizedImg;
        }
        else if(angle==180)
        {
            BufferedImage resizedImg=new BufferedImage(srcImg.getWidth(),srcImg.getHeight(),BufferedImage.TRANSLUCENT);
            for(int i=0;i<srcImg.getWidth();++i)
            {
                for(int j=0;j<srcImg.getHeight();++j)
                {resizedImg.setRGB(srcImg.getWidth()-1-i,srcImg.getHeight()-1-j,srcImg.getRGB(i,j));}
            }
            return resizedImg;
        }
        else if(angle==270)
        {
            BufferedImage resizedImg=new BufferedImage(srcImg.getHeight(),srcImg.getWidth(),BufferedImage.TRANSLUCENT);
            for(int i=0;i<srcImg.getWidth();++i)
            {
                for(int j=0;j<srcImg.getHeight();++j)
                {resizedImg.setRGB(j,srcImg.getWidth()-1-i,srcImg.getRGB(i,j));}
            }
            return resizedImg;
        }
        return srcImg;
    }

    private BufferedImage getScaledImage(BufferedImage srcImg,int w,int h)
    {
        BufferedImage resizedImg=new BufferedImage(w,h,BufferedImage.TRANSLUCENT);
        Graphics2D g2=resizedImg.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2.drawImage(srcImg.getScaledInstance(w,h,Image.SCALE_SMOOTH),0,0,w,h,null);
        g2.dispose();
        return resizedImg;
    }

    public void stateChanged(ChangeEvent e)
    {
        update();
    }

    @Override
    public void restart()
    {
        dispose();
        main();
    }

    public static void main()
    {
        main(new String[0]);
    }
}
